use crate::Vector3::Vector3;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Line3 {
    pub p: Vector3,
    // 点
    pub u: Vector3, // 方向
}

impl Line3 {
    pub fn new(p: Vector3, u: Vector3) -> Self {
        Self { p, u }
    }

    /**
     * http://geomalgorithms.com/a07-_distance.html
     * 线与线的距离
     * D 为0 平行
     * 距离为0，就是相交
     */
    pub fn distance(&self, l: &Line3, epsilon: f64) -> f64 {
        let u = &self.u;
        let v = &l.u;
        let w = self.p.subtract(&l.p);
        let a = u.dot(&u); // always >= 0
        let b = u.dot(&v);
        let c = v.dot(&v); // always >= 0
        let d = u.dot(&w);
        let e = v.dot(&w);
        let d = a * c - b * b; // always >= 0
        let mut sc;
        let mut tc;

        // compute the line parameters of the two closest points
        if d < epsilon {
            // the lines are almost parallel
            sc = 0.0;
            tc = if b > c { d / b } else { e / c }; // use the largest denominator
        } else {
            sc = (b * e - c * d) / d;
            tc = (a * e - b * d) / d;
        }

        // get the difference of the two closest points
        //const dP = w + sc * u - tc * v; // =  L1(sc) - L2(tc)
        let dP = w.add(&u.multiply(sc)).subtract(&v.multiply(tc));

        return dP.length(); // return the closest distance
    }
}
